home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Datafile PD-CD 1 Issue 2
/
PDCD-1 - Issue 02.iso
/
_utilities
/
utilities
/
003
/
_gs
/
!GS
/
ps
/
BDFTOPS
< prev
next >
Wrap
Text File
|
1991-10-25
|
24KB
|
745 lines
% Copyright (C) 1990, 1991 Aladdin Enterprises. All rights reserved.
% Distributed by Free Software Foundation, Inc.
%
% This file is part of Ghostscript.
%
% Ghostscript is distributed in the hope that it will be useful, but
% WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
% to anyone for the consequences of using it or for whether it serves any
% particular purpose or works at all, unless he says so in writing. Refer
% to the Ghostscript General Public License for full details.
%
% Everyone is granted permission to copy, modify and redistribute
% Ghostscript, but only under the conditions described in the Ghostscript
% General Public License. A copy of this license is supposed to have been
% given to you along with Ghostscript so you can know your rights and
% responsibilities. It should be in a file named COPYING. Among other
% things, the copyright notice and this notice must be preserved on all
% copies.
% bdftops.ps
% Convert a BDF file to a Ghostscript font.
% Ghostscript fonts are in the same format as Adobe Type 1 fonts,
% except that they do not use eexec encryption.
% See gfonts.ps for more information.
/envBDF 120 dict def
envBDF begin
% Define whether to write out the CharStrings in binary or in hex.
% Binary takes less space on the file, but isn't guaranteed portable.
/binary false def
% Define lenIV (the number of initial random bytes in the encoded outlines).
% This should be zero, but we set it to 4 for compatibility with PostScript.
/lenIV 4 def
% Invert the StandardEncoding vector.
256 dict dup begin
0 1 255 { dup StandardEncoding exch get exch def } for
end /decoding exch def
% Define the dictionary equivalent of ].
/dicttomark
{ counttomark 2 idiv dup dict begin
{ def } repeat
pop currentdict end
} bind def
% Define the character sequences used to fill in some undefined entries
% in the standard encoding.
mark
(exclamdown) [/exclam]
(fraction) [/slash]
(florin) [/f]
(quotesingle) [/quoteright]
(quotedblleft) [/quotedbl]
(guillemotleft) [/less /less]
(guilsinglleft) [/less]
(guilsinglright) [/greater]
(fi) [/f /i]
(fl) [/f /l]
(endash) [/hyphen /hyphen]
(periodcentered) [/asterisk]
(bullet) [/asterisk]
(quotesinglbase) [/quotesingle]
(quotedblbase) [/quotedbl]
(quotedblright) [/quotedbl]
(guillemotright) [/greater /greater]
(ellipsis) [/period /period /period]
(questiondown) [/question]
(grave) [/quoteleft]
(acute) [/quoteright]
(circumflex) [/asciicircum]
(tilde) [/asciitilde]
(dieresis) [/quotedbl]
(cedilla) [/comma]
(hungarumlaut) [/quotedbl]
(emdash) [/hyphen /hyphen /hyphen]
(AE) [/A /E]
(OE) [/O /E]
(ae) [/a /e]
(dotlessi) [/i]
(oe) [/o /e]
(germandbls) [/s /s]
dicttomark /composites exch def
% Note the characters that must be defined as subroutines.
96 dict begin
0 composites
{ exch pop
{ dup currentdict exch known
{ pop }
{ 1 index def 1 add }
ifelse
}
forall
}
forall pop
currentdict
end /subrchars exch def
% Define the overstruck characters that can be synthesized with seac.
mark
[ /Aacute /Acircumflex /Adieresis /Agrave /Aring /Atilde
/Ccedilla
/Eacute /Ecircumflex /Edieresis /Egrave
/Iacute /Icircumflex /Idieresis /Igrave
/Ntilde
/Oacute /Ocircumflex /Odieresis /Ograve /Otilde
/Scaron
/Uacute /Ucircumflex /Udieresis /Ugrave
/Yacute /Ydieresis
/Zcaron
/aacute /acircumflex /adieresis /agrave /aring /atilde
/ccedilla
/eacute /ecircumflex /edieresis /egrave
/iacute /icircumflex /idieresis /igrave
/ntilde
/oacute /ocircumflex /odieresis /ograve /otilde
/scaron
/uacute /ucircumflex /udieresis /ugrave
/yacute /ydieresis
/zcaron
]
{ dup dup length string cvs
[ exch dup 0 1 getinterval
exch dup length 1 sub 1 exch getinterval
]
} forall
/cent [/c /slash]
/sterling [/L /hyphen]
/yen [/Y /equal]
/daggerdbl [/bar /equal]
dicttomark /accentedchars exch def
% Load the utility procedures.
(fcutils.ps) run
% Define the Type 1 opcodes we care about.
/c_callsubr 10 def /s_callsubr <0a> def
/c_return 11 def
/c_escape 12 def
/ce_seac 6 def /s_seac <0c06> def
/ce_sbw 7 def /s_sbw <0c07> def
/ce_setcurrentpoint 33 def /s_setcurrentpoint <0c21> def
/c_hsbw 13 def /s_hsbw <0d> def
/c_endchar 14 def /s_endchar <0e> def
/c_hmoveto 22 def
/s_setcurrentpoint_hmoveto s_setcurrentpoint <8b16> concatstrings def
% ------ BDF file parsing utilities ------ %
% Define a buffer for reading the BDF file.
/buffer 400 string def
% Read a line from the BDF file into the buffer.
% Define /keyword as the first word on the line.
% Define /args as the remainder of the line.
% If the keyword is equal to commentword, skip the line.
% (If commentword is equal to a space, never skip.)
/commentword ( ) def
/nextline
{ bdfile buffer readline not
{ (Premature EOF\n) print stop } if
( ) search
{ /keyword exch def pop }
{ /keyword exch def () }
ifelse
/args exch def
keyword commentword eq { nextline } if
} bind def
% Get an integer argument from args.
/iarg % iarg -> int
{ args ( ) search
{ cvi exch pop exch }
{ cvi () }
ifelse /args exch def
} bind def
% Convert the remainder of args into a string.
/remarg % remarg -> string
{ args copystring
} bind def
% Get a string argument that occupies the remainder of args.
/sarg % sarg -> string
{ args (") anchorsearch
{ pop /args exch def } { pop } ifelse
args args length 1 sub get (") 0 get eq
{ args 0 args length 1 sub getinterval /args exch def } if
args copystring
} bind def
% Check that the keyword is the expected one.
/checkline % (EXPECTED-KEYWORD) checkline ->
{ dup keyword ne
{ (Expected ) print =
(Line=) print keyword print ( ) print args print (\n) print stop
} if
pop
} bind def
% Read a line and check its keyword.
/getline % (EXPECTED-KEYWORD) getline ->
{ nextline checkline
} bind def
% Find the first/last non-zero bit of a non-zero byte.
/fnzb
{ 0 { exch dup 128 ge { pop exit } { dup add exch 1 add } ifelse }
loop
} bind def
/lnzb
{ 7 { exch dup 1 and 0 ne { pop exit } { -1 bitshift exch 1 sub } ifelse }
loop
} bind def
% ------ Bitmap analysis utilities ------ %
% Find the first and last bit of a row of bits.
% Arguments: (cbits) (craster) y.
% Result: lastbit firstbit.
/findends
{ craster mul cbits exch craster getinterval /row exch def
0 row length 1 sub -1 0
{ dup row exch get 0 ne
{ exch pop dup row exch get lnzb exch 8 mul add exit }
{ pop } ifelse
} for
row length 8 mul 0 1 row length 1 sub
{ dup row exch get 0 ne
{ exch pop dup row exch get fnzb exch 8 mul add exit }
{ pop } ifelse
} for
} bind def
% Determine the slant of a bitmap.
% Arguments: cbits craster.
% Result: dx dy of slant.
/findslant
{ /craster exch def /cbits exch def
cbits length craster idiv /height exch def
% Find the width in the middle of the character.
height 2 idiv dup /top exch def dup /bot exch def
findends sub /midw exch def
% Find the top and bottom of the uniform part.
{ top 0 eq { exit } if
top 1 sub findends sub midw sub
dup -1 lt { pop exit } if 1 gt { exit } if
top 1 sub /top exch def
} loop
{ bot 1 add height eq { exit } if
bot 1 add findends sub midw sub
dup -1 lt { pop exit } if 1 gt { exit } if
bot 1 add /bot exch def
} loop
% Report the slant.
top findends add 2 idiv
bot findends add 2 idiv sub
bot top sub
} bind def
% ------ Type 1 encoding utilities ------ %
% Parse the side bearing and width information that begins a CharString.
% Arguments: charstring. Result: mark sbx wx substring *or*
% mark sbx sby wx wy substring.
/parsesbw
{ mark exch lenIV
{ % stack: mark ... string dropcount
dup 2 index length exch sub getinterval
dup 0 get dup 32 lt { pop exit } if
dup 246 le
{ 139 sub exch 1 }
{ dup 250 le
{ 247 sub 8 bitshift 108 add 1 index 1 get add exch 2 }
{ dup 254 le
{ 251 sub 8 bitshift 108 add 1 index 1 get add neg exch 2 }
{ pop dup 1 get 128 xor 128 sub
8 bitshift 1 index 2 get add
8 bitshift 1 index 3 get add
8 bitshift 1 index 4 get add exch 5
} ifelse
} ifelse
} ifelse
} loop
} bind def
% Find the side bearing and width information that begins a CharString.
% Arguments: charstring. Result: charstring sizethroughsbw.
/findsbw
{ dup parsesbw counttomark 1 add 1 roll cleartomark skipsbw
} bind def
/skipsbw % charstring sbwprefix -> sizethroughsbw
{ length 1 index length exch sub
2 copy get 12 eq { 2 } { 1 } ifelse add
} bind def
% Encode a number, and append it to a string.
% Arguments: str num. Result: newstr.
/concatnum
{ dup dup -107 ge exch 107 le and
{ 139 add 1 string dup 0 3 index put }
{ dup dup -1131 ge exch 1131 le and
{ dup 0 ge { 16#f694 } { neg 16#fa94 } ifelse add
2 string dup 0 3 index -8 bitshift put
dup 1 3 index 255 and put
}
{ 5 string dup 0 255 put exch
2 copy 1 exch -24 bitshift 255 and put
2 copy 2 exch -16 bitshift 255 and put
2 copy 3 exch -8 bitshift 255 and put
2 copy 4 exch 255 and put
exch
}
ifelse
}
ifelse exch pop concatstrings
} bind def
% Encode a subroutine call for a given character, appending it to a string.
% Arguments: str subrindex. Result: newstr.
/concatcall
{ () exch concatnum
s_callsubr concatstrings concatstrings
} bind def
% ------ Point arithmetic utilities ------ %
/ptadd { exch 4 -1 roll add 3 1 roll add } bind def
/ptexch { 4 2 roll } bind def
/ptneg { neg exch neg exch } bind def
/ptsub { ptneg ptadd } bind def
% ------ Output utilities ------ %
% Define some utilities for writing the output file.
/wtstring 100 string def
/ws {psfile exch writestring} bind def
/wl {ws (\n) ws} bind def
/wt {wtstring cvs ws ( ) ws} bind def
/wo {psfile exch write==only ( ) ws} bind def
% Encrypt and write a hex string for Subrs or CharStrings.
% Note that this smashes the string being written.
/wx
{ 4330 exch dup type1encrypt exch pop
(_R ) ws dup length wt
binary
{ ws
}
{ % Some systems choke on very long lines, so
% we break up the hexstring into chunks of 50 characters.
{ dup length 25 le {exit} if
dup 0 25 getinterval psfile exch writehexstring (\n) ws
dup length 25 sub 25 exch getinterval
} loop
psfile exch writehexstring
} ifelse
} bind def
% Write a character definition.
/wcdef
{ (/) ws exch ws ( ) ws wx ( _D) wl
} bind def
% ------ The main program ------ %
/bdftops % infilename outfilename mapfilename bdftops ->
{ /mapname exch def
/psname exch def
/bdfname exch def
gsave % so we can set the CTM to the font matrix
% Open the input files. We don't open the output file until
% we've done a minimal validity check on the input.
bdfname (r) file /bdfile exch def
mapname findlibfile not
{ (bdftops: Can't find map file ) print print (!\n) print stop }
if
/mapfile exch def
% Check for the STARTFONT.
(STARTFONT) getline
args (2.1) ne { (Not version 2.1\n) print stop } if
% Look up the output file name in the font map.
mapfile psname fontmapfind
/uniqueID exch def
/encoding exch def
/fontname exch def
% Now open the output file.
psname (w) file /psfile exch def
% Put out a header compatible with the Adobe "standard".
(%!FontType1-1.0: ) ws fontname wt (000.000) wl
% Copy the leading comments, up to FONT.
(% This is a font description converted from ) ws
bdfname ws (.) wl
true
{ nextline
keyword (COMMENT) ne {exit} if
{ (% Here are the leading comments from the BDF file:\n%) wl
} if false
(%) ws remarg wl
} loop pop
/commentword (COMMENT) def % do skip comments from now on
% Read and process the FONT, SIZE, and FONTBOUNDINGBOX.
% If we cared about FONT, we'd use it here. If the BDF files
% from MIT had PostScript names rather than X names, we would
% care; but what's there is unusable, so we discard FONT.
(FONT) checkline
(SIZE) getline
/pointsize iarg def /xres iarg def /yres iarg def
(FONTBOUNDINGBOX) getline
/fbbw iarg def /fbbh iarg def /fbbxo iarg def /fbbyo iarg def
/fraster fbbw 7 add 8 idiv def
nextline
% Allocate the buffers for the bitmap and the outline,
% according to the font bounding box.
/bits fraster fbbh mul 200 max 65535 min string def
/outline bits length 6 mul 65535 min string def
/iangles 0 def /iacount 0 def
% The Type 1 font machinery really only works with a 1000 unit
% character coordinate system. Set this up here.
% Compute the factor to make the X entry in the FontMatrix
% come out at exactly 0.001.
/fontscale 72 pointsize div xres div 1000 mul def
% Read and process the properties. We only care about a few of them.
/pcount 0 def
keyword (STARTPROPERTIES) eq
{ iarg
{ nextline
keyword (COPYRIGHT) eq
keyword (FULL_NAME) eq or
keyword (FAMILY_NAME) eq or
keyword (WEIGHT_NAME) eq or
{ keyword cvn sarg def
/pcount pcount 1 add def
} if
} repeat
(ENDPROPERTIES) getline
nextline
} if
% Compute and set the eventual FontMatrix.
[ 0.001 0 0 0.001 xres mul yres div 0 0 ] setmatrix
% Read and process the header for the bitmaps.
(CHARS) checkline
/ccount iarg def
% Initialize the character subroutine table and the CharStrings dictionary.
/subrs subrchars length array def
/subrsbw subrchars length array def
/subrcount 0 def
/charstrings ccount composites length add
accentedchars length add dict def
/isfixedwidth true def
/fixedwidth null def
% Read and process the bitmap data. This reads the remainder of the file.
ccount -1 1
{ (STARTCHAR) getline
/charname remarg def
(/) print charname print
10 mod 1 eq { (\n) print flush } if
(ENCODING) getline % Ignore, assume StandardEncoding
(SWIDTH) getline
/swx iarg pointsize mul 1000 div xres mul 72 div def
/swy iarg pointsize mul 1000 div xres mul 72 div def
(DWIDTH) getline % Ignore, use SWIDTH instead
(BBX) getline
/bbw iarg def /bbh iarg def /bbox iarg def /bboy iarg def
nextline
keyword (ATTRIBUTES) eq
{ nextline
} if
(BITMAP) checkline
% Read the bits for this character.
bbw 7 add 8 idiv /raster exch def
% The bitmap handed to type1imagepath must have the correct height,
% because type1imagepath uses this to compute the scale factor,
% so we have to clear the unused parts of it.
bits dup 0 1 raster fbbh mul 1 sub
{ 0 put dup } for
pop pop
raster fbbh bbh sub mul raster raster fbbh 1 sub mul
{ bits exch raster getinterval
bdfile buffer readline not
{ (EOF in bitmap\n) print stop } if
exch readhexstring pop pop pop
} for
(ENDCHAR) getline
% Compute the font entry, converting the bitmap to an outline.
bits 0 raster fbbh mul getinterval % the bitmap image
bbw fbbh % bitmap width & height
swx swy % width x & y
bbox neg bboy neg % origin x & y
% Account for lenIV when converting the outline.
outline lenIV outline length lenIV sub getinterval
type1imagepath
length lenIV add
outline exch 0 exch getinterval
% Check for a fixed width font.
isfixedwidth
{ fixedwidth null eq
{ /fixedwidth swx def }
{ fixedwidth swx ne { /isfixedwidth false def } if }
ifelse
} if
% Use this character to determine italic angle if plausible.
charname (I) eq charname (l) eq or
{ bits 0 raster fbbh mul getinterval raster findslant
2 copy or 0 ne
{ atan iangles add /iangles exch def
iacount 1 add /iacount exch def
}
{ pop pop
} ifelse
} if
% Check whether this character must be a subroutine.
% If so, strip off the initial [h]sbw, replace the endchar by a return,
% and put the charstring in the Subrs array.
subrchars charname known
{ /charstr exch def
/csindex subrchars charname get def
charstr parsesbw counttomark 1 add 1 roll
counttomark 2 eq { 0 exch 0 } if ]
subrsbw exch csindex exch put
charstr exch skipsbw /charend exch def pop
charstr charstr length 1 sub c_return put
subrs csindex
charstr charend lenIV sub dup charstr length exch sub
getinterval copystring
put
charstr 0 charend getinterval
() subrchars charname get concatcall s_endchar concatstrings
concatstrings
/subrcount subrcount 1 add def
}
{ copystring }
ifelse
charname exch charstrings 3 1 roll put
} for
(ENDFONT) getline
% Synthesize missing characters out of available ones.
% For fixed-width fonts, only do this in the 1-for-1 case.
composites
{ 1 index charstrings exch known
{ pop pop }
{ dup isfixedwidth
{ dup length 1 eq }
{ true }
ifelse
exch { charstrings exch known and } forall
{ ( /) print 1 index bits cvs print
dup length 1 eq
{ 0 get charstrings exch get copystring }
{ % Top of stack is array of characters to combine.
% Convert to an array of subr indices.
[ exch { subrchars exch get } forall ]
% The final width is the sum of the widths of all
% the characters, minus the side bearings of all the
% characters except the first. After each character
% except the last, do a setcurrentpoint of its width
% minus its side bearing (except for the first character);
% before each character except the first, do a 0 hmoveto.
% Fortunately, all this information is available in subrsbw.
/combine exch def
lenIV string
% Compute the total width.
subrsbw combine 0 get get aload pop pop pop 2 copy
combine
{ subrsbw exch get
aload pop ptexch ptsub ptadd
} forall
% Encode the combined side bearing and width.
dup 3 index or 0 eq
{ pop exch pop 2 array astore s_hsbw }
{ 4 array astore s_sbw }
ifelse
3 1 roll { concatnum } forall exch concatstrings
% Encode the subroutine calls, except the last.
subrsbw combine 0 get get aload pop ptexch pop pop
0 1 combine length 2 sub
{ combine exch get /ccsi exch def
2 copy 5 -1 roll ccsi concatcall
3 -1 roll concatnum exch concatnum
s_setcurrentpoint_hmoveto concatstrings
subrsbw ccsi get aload pop ptexch ptsub
5 -2 roll ptadd
} for
% Encode the last call.
pop pop
combine dup length 1 sub get concatcall
s_endchar concatstrings
} ifelse
charstrings 3 1 roll put
}
{ pop pop }
ifelse
}
ifelse
}
forall flush
% Synthesize accented characters with seac if needed and possible.
accentedchars
{ aload pop /accent exch def /base exch def
buffer cvs /accented exch def
charstrings accented known not
charstrings base known and
charstrings accent known and
{ ( /) print accented print
charstrings base get findsbw 0 exch getinterval
/acstring exch def % start with sbw of base
charstrings accent get parsesbw
counttomark 1 sub { pop } repeat % just leave mark & sbx
acstring exch concatnum exch pop % pop the mark
0 concatnum 0 concatnum % adx ady
decoding base get concatnum % bchar
decoding accent get concatnum % achar
s_seac concatstrings
charstrings exch accented copystring exch put
} if
} forall
% Write out the creation of the font dictionary and FontInfo.
(12 dict begin) wl
(/FontInfo ) ws pcount 2 add wt (dict dup begin) wl
(/isFixedPitch ) ws isfixedwidth wt (def) wl
(/ItalicAngle ) ws
iacount 0 eq
{ (0 ) ws }
{ iangles iacount div 5 div round 5 mul cvi wt }
ifelse (def) wl
currentdict /COPYRIGHT known
{ (/Notice ) ws COPYRIGHT wo (readonly def) wl } if
currentdict /FULL_NAME known
{ (/FullName ) ws FULL_NAME wo (readonly def) wl } if
currentdict /FAMILY_NAME known
{ (/FamilyName ) ws FAMILY_NAME wo (readonly def) wl } if
currentdict /WEIGHT_NAME known
{ (/Weight ) ws WEIGHT_NAME wo (readonly def) wl } if
(end readonly def) wl
% Write out the other fixed entries in the font dictionary.
(/FontName ) ws fontname wo (def) wl
(/PaintType 0 def) wl
(/FontType 1 def) wl
(/FontMatrix [ ) ws
matrix currentmatrix {wt} forall
(] readonly def) wl
(/Encoding ) ws encoding wt (def) wl
fontscale
(/FontBBox { ) ws
dup fbbxo mul wt dup fbbyo mul wt
dup fbbxo fbbw add mul wt dup fbbyo fbbh add mul wt
(} readonly def) wl
pop
(/UniqueID ) ws uniqueID wt (def) wl % uniqueID is an integer
(currentdict end) wl
% The rest of the file could be in eexec form, but we don't see any point
% in doing this, because we aren't attempting to conceal it from anyone.
% Create and initialize the Private dictionary.
(dup /Private 9 dict dup begin) wl
(/_D {readonly def} readonly def) wl
(/_P {readonly put} _D) wl
(/_R {currentfile token pop string currentfile exch ) ws
binary {(readstring)} {(readhexstring)} ifelse ws
( pop} _D) wl
(/BlueValues [] def) wl
(/lenIV ) ws lenIV wt (def) wl
(/MinFeature {16 16} def) wl
(/password 5839 def) wl
(/UniqueID ) ws uniqueID wt (def) wl
% Write the Subrs entries, if any.
subrcount 0 gt
{ (/Subrs ) ws subrs length wt (array) wl
0 1 subrs length 1 sub
{ dup subrs exch get dup null ne
{ (dup ) ws exch wo wx ( _P) wl }
{ pop pop }
ifelse
} for
(_D) wl
}
if
% Write all the CharStrings entries.
(2 index /CharStrings ) ws charstrings length 1 add wt
(dict dup begin) wl
charstrings { wcdef } forall
% Write the CharStrings entry for .notdef.
outline lenIV <8b8b0d0e> putinterval % 0 0 hsbw endchar
(.notdef) outline 0 lenIV 4 add getinterval wcdef
% Wrap up the private part of the font.
(end) wl % CharStrings
(end) wl % Private
(readonly put) wl % CharStrings
(readonly put) wl % Private
% Write the other standard entries in the font dictionary.
(dup begin) wl
(end) wl
% Terminate the output, and close the files.
(dup /FontName get exch definefont pop) wl
bdfile closefile
psfile closefile
(\n) print flush
grestore
} bind def
end
% Enter the main program in the current dictionary.
/bdftops
{ envBDF begin (Fontmap) bdftops end
} bind def
% If the program was invoked from the command line, run it now.
shellarguments { bdftops } if